package com.slog.s7;

import android.text.TextUtils;

import androidx.annotation.Nullable;

import com.slog.s7.utils.BaseLog;
import com.slog.s7.utils.FileLog;
import com.slog.s7.utils.JsonLog;
import com.slog.s7.utils.Constant;
import com.slog.s7.utils.XmlLog;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * This is a Log tool，with this you can the following
 *  * <ol>
 *  * <li>use SLog.d(),you could print whether the method execute,and the default tag is current class's name</li>
 *  * <li>use SLog.d(msg),you could print log as before,and you could location the method with a click in Android Studio Logcat</li>
 *  * <li>use SLog.json(),you could print json string with well format automatic</li>
 *  * </ol>
 * 加对文件的支持、对XML的支持、对任意参数的支持、对无限长字符串支持、对自定义全局Tag的支持
 *  SLog.debug(),用于发布版本的Log打印,优化部分代码、堆栈跟踪功能SLog.trace()
 */
public class SLog {
    private static String mGlobalTag;
    private static boolean mIsGlobalTagEmpty = true;
    private static boolean IS_SHOW_LOG = true;

    /**
     * 初始化
     * @param isShowLog
     */
    public static void init(boolean isShowLog) {
        IS_SHOW_LOG = isShowLog;
    }

    public static void init(boolean isShowLog, @Nullable String tag) {
        IS_SHOW_LOG = isShowLog;
        mGlobalTag = tag;
        mIsGlobalTagEmpty = TextUtils.isEmpty(mGlobalTag);
    }

    public static void v() {
        printLog(Constant.V, null, Constant.DEFAULT_MESSAGE);
    }

    public static void v(Object msg) {
        printLog(Constant.V, null, msg);
    }

    public static void v(String tag, Object... objects) {
        printLog(Constant.V, tag, objects);
    }

    public static void d() {
        printLog(Constant.D, null, Constant.DEFAULT_MESSAGE);
    }

    public static void d(Object msg) {
        printLog(Constant.D, null, msg);
    }

    public static void d(String tag, Object... objects) {
        printLog(Constant.D, tag, objects);
    }

    public static void i() {
        printLog(Constant.I, null, Constant.DEFAULT_MESSAGE);
    }

    public static void i(Object msg) {
        printLog(Constant.I, null, msg);
    }

    public static void i(String tag, Object... objects) {
        printLog(Constant.I, tag, objects);
    }

    public static void w() {
        printLog(Constant.W, null, Constant.DEFAULT_MESSAGE);
    }

    public static void w(Object msg) {
        printLog(Constant.W, null, msg);
    }

    public static void w(String tag, Object... objects) {
        printLog(Constant.W, tag, objects);
    }

    public static void e() {
        printLog(Constant.E, null, Constant.DEFAULT_MESSAGE);
    }

    public static void e(Object msg) {
        printLog(Constant.E, null, msg);
    }

    public static void e(String tag, Object... objects) {
        printLog(Constant.E, tag, objects);
    }

    public static void a() {
        printLog(Constant.A, null, Constant.DEFAULT_MESSAGE);
    }

    public static void a(Object msg) {
        printLog(Constant.A, null, msg);
    }

    public static void a(String tag, Object... objects) {
        printLog(Constant.A, tag, objects);
    }

    public static void json(String jsonFormat) {
        printLog(Constant.JSON, null, jsonFormat);
    }

    public static void json(String tag, String jsonFormat) {
        printLog(Constant.JSON, tag, jsonFormat);
    }

    public static void xml(String xml) {
        printLog(Constant.XML, null, xml);
    }

    public static void xml(String tag, String xml) {
        printLog(Constant.XML, tag, xml);
    }

    public static void file(File targetDirectory, Object msg) {
        printFile(null, targetDirectory, null, msg);
    }

    public static void file(String tag, File targetDirectory, Object msg) {
        printFile(tag, targetDirectory, null, msg);
    }

    public static void file(String tag, File targetDirectory, String fileName, Object msg) {
        printFile(tag, targetDirectory, fileName, msg);
    }

    public static void debug() {
        printDebug(null, Constant.DEFAULT_MESSAGE);
    }

    public static void debug(Object msg) {
        printDebug(null, msg);
    }

    public static void debug(String tag, Object... objects) {
        printDebug(tag, objects);
    }

    public static void trace() {
        printStackTrace();
    }

    private static void printStackTrace() {

        if (!IS_SHOW_LOG) {
            return;
        }

        Throwable tr = new Throwable();
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        tr.printStackTrace(pw);
        pw.flush();
        String message = sw.toString();

        String traceString[] = message.split("\\n\\t");
        StringBuilder sb = new StringBuilder();
        sb.append("\n");
        for (String trace : traceString) {
            if (trace.contains("at com.slog.s7.SLog")) {
                continue;
            }
            sb.append(trace).append("\n");
        }
        String[] contents = wrapperContent(Constant.STACK_TRACE_INDEX_4, null, sb.toString());
        String tag = contents[0];
        String msg = contents[1];
        String headString = contents[2];
        BaseLog.printDefault(Constant.D, tag, headString + msg);
    }

    /**
     * 普通日志
     * @param type
     * @param tagStr
     * @param objects
     */
    private static void printLog(int type, String tagStr, Object... objects) {

        if (!IS_SHOW_LOG) {
            return;
        }

        String[] contents = wrapperContent(Constant.STACK_TRACE_INDEX_5, tagStr, objects);
        String tag = contents[0];
        String msg = contents[1];
        String headString = contents[2];

        switch (type) {
            case Constant.V:
            case Constant.D:
            case Constant.I:
            case Constant.W:
            case Constant.E:
            case Constant.A:
                BaseLog.printDefault(type, tag, headString + msg);
                break;
            case Constant.JSON:
                JsonLog.printJson(tag, msg, headString);
                break;
            case Constant.XML:
                XmlLog.printXml(tag, msg, headString);
                break;
        }

    }

    /**
     * Debug 日志
     * @param tagStr
     * @param objects
     */
    private static void printDebug(String tagStr, Object... objects) {
        String[] contents = wrapperContent(Constant.STACK_TRACE_INDEX_5, tagStr, objects);
        String tag = contents[0];
        String msg = contents[1];
        String headString = contents[2];
        BaseLog.printDefault(Constant.D, tag, headString + msg);
    }

    /**
     * 文件日志
     * @param tagStr
     * @param targetDirectory
     * @param fileName
     * @param objectMsg
     */
    private static void printFile(String tagStr, File targetDirectory, String fileName, Object objectMsg) {

        if (!IS_SHOW_LOG) {
            return;
        }

        String[] contents = wrapperContent(Constant.STACK_TRACE_INDEX_5, tagStr, objectMsg);
        String tag = contents[0];
        String msg = contents[1];
        String headString = contents[2];

        FileLog.printFile(tag, targetDirectory, fileName, headString, msg);
    }

    /**
     * 格式化Log内容
     * @param stackTraceIndex
     * @param tagStr 标签
     * @param objects
     * @return 标签/消息/打印位置
     */
    private static String[] wrapperContent(int stackTraceIndex, String tagStr, Object... objects) {

        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

        StackTraceElement targetElement = stackTrace[stackTraceIndex];
        String className = targetElement.getClassName();
        String[] classNameInfo = className.split("\\.");
        if (classNameInfo.length > 0) {
            className = classNameInfo[classNameInfo.length - 1] + Constant.SUFFIX;
        }

        if (className.contains("$")) {
            className = className.split("\\$")[0] + Constant.SUFFIX;
        }

        String methodName = targetElement.getMethodName();
        int lineNumber = targetElement.getLineNumber();

        if (lineNumber < 0) {
            lineNumber = 0;
        }

        String tag = (tagStr == null ? className : tagStr);

        if (mIsGlobalTagEmpty && TextUtils.isEmpty(tag)) {
            tag = Constant.TAG_DEFAULT;
        } else if (!mIsGlobalTagEmpty) {
            tag = mGlobalTag;
        }
        String msg = (objects == null) ? Constant.NULL_TIPS : getObjectsString(objects);
        String headString = "[ (" + className + ":" + lineNumber + ")#" + methodName + " ] ";

        return new String[]{tag, msg, headString};
    }

    /**
     * 消息内容处理
     * @param objects
     * @return
     */
    private static String getObjectsString(Object... objects) {

        if (objects.length > 1) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("\n");
            for (int i = 0; i < objects.length; i++) {
                Object object = objects[i];
                if (object == null) {
                    stringBuilder.append(Constant.PARAM).append("[").append(i).
                            append("]").append(" = ").append(Constant.NULL).append("\n");
                } else {
                    stringBuilder.append(Constant.PARAM).append("[").append(i).append("]").append(" = ")
                            .append(object.toString()).append("\n");
                }
            }
            return stringBuilder.toString();
        } else {
            Object object = objects[0];
            return object == null ? Constant.NULL : object.toString();
        }
    }
}
